﻿// ReSharper disable CppClangTidyModernizeUseNodiscard
#pragma once
#include "Material.h"
#include "Texture2D.h"
#include "Path.h"
#include "ShaderProgram.h"

class FCubeLightMapMaterial final
	: public FMaterial
{
private:

	std::shared_ptr<FTexture2D> TextureDiffuse;

	std::shared_ptr<FTexture2D> TextureSpecular;

public:

	virtual bool Init() override
	{
		if (!FMaterial::Init())
		{
			return false;
		}

		FTextureBuild Build;
		TextureDiffuse = Build.Build(FPath::BuildImgPath("container2.png"), true);

		Build.Reset();
		TextureSpecular = Build.Build(FPath::BuildImgPath("container2_specular.png"), true);

		Shader->Use();

		Shader->SetInt("material.diffuse", 0);
		Shader->SetInt("material.specular", 1);

		return true;
	}

	virtual void Use() override
	{
		FMaterial::Use();

		TextureDiffuse->BindTextureUnit(0);
		TextureSpecular->BindTextureUnit(1);
	}

	const std::string& GetFsSrcCode() const override
	{
		static std::string CodeStr = R"(
			#version 410 core

			struct Material
			{
				// 漫反射贴图
			    sampler2D   diffuse;
				// 镜面光照的颜色
			    sampler2D  specular;
				// 反光度
				// 越大  亮点越小 光束越集中
			    float shininess;
			}; 

			struct Light
			{
			    vec3 position;
			    vec3 ambient;
			    vec3 diffuse;
			    vec3 specular;
			};
			
			out vec4 FragColor;

			in vec3 Normal;
			in vec3 FragPos;
			in vec2 TexCoords;
			
			uniform vec3 viewPos;
			uniform Material material;
			uniform Light light;

			void main()
			{
				vec3 norm = normalize(Normal);
				// 光的方向
				vec3 lightDir = normalize(light.position - FragPos);

				// Dot 值在  半个周期中 角度越大值越小
				// 值如果是负的 说明 被挡了 压根不应该有颜色，所以保底是 0
				float diff = max(dot(norm, lightDir), 0.0);
				vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));

				// 环境光  实际上 环境光 和 漫反射的颜色总是相同的
				vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));

				// 镜面高光
				float specularStrength = 0.5;
				vec3 viewDir = normalize(viewPos - FragPos);
				//reflect  光指向片元的向量 ,  法线
				vec3 reflectDir = reflect(-lightDir, norm);
			
				// pow  次幂
				float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
				vec3 specular = light.specular * vec3(texture(material.specular, TexCoords)) * spec;

				vec3 result = ambient + diffuse + specular;
				FragColor = vec4(result, 1.0);

				//FragColor = texture(material.specular, TexCoords);
			}
		)";

		return CodeStr;
	}

	const std::string& GetVsSrcCode() const override
	{
		static std::string CodeStr = R"(

			#version 410 core 
			
			layout (location = 0) in vec3 aPos;
			layout (location = 1) in vec3 aNormal;
			layout (location = 2) in vec2 aTexCoords;

			uniform mat4 model;
			uniform mat4 view;
			uniform mat4 projection;

			out vec3 Normal;
			out vec3 FragPos;
			out vec2 TexCoords;

			void main()
			{
			    gl_Position = projection *  view * model * vec4(aPos, 1.0);

				// 给片段着色器法线  法线矩阵
				//http://www.lighthouse3d.com/tutorials/glsl-12-tutorial/the-normal-matrix/
				Normal = mat3(transpose(inverse(model))) * aNormal;

				// 给片段着色器 顶点在世界空间中的位置
				FragPos = vec3(model * vec4(aPos, 1.0));

				TexCoords = aTexCoords;
			}

		)";

		return CodeStr;
	}
};

